#include <string.h>

#include <driver/gpio.h>
#include <driver/spi_master.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_log.h>

#include "interface.h"

// 在此处配置接口
static const int rst_io_num = 0;
static const int miso_io_num = 2; // FSPIQ
static const int mosi_io_num = 7; // FSPID
static const int sclk_io_num = 6; // FSPICLK
static const int cs_io_num = 10; // FSPI
static const spi_host_device_t host_id = SPI2_HOST;
static const spi_dma_chan_t dma_chan = SPI_DMA_CH_AUTO;

static spi_device_handle_t spi_device_handle;

static esp_err_t ret;

static const char *TAG = "rc522_interface";

static inline void log_if_err(const esp_err_t e, const char *string)
{
	if (e != ESP_OK)
		ESP_LOGE(TAG, "%s error: %s", string, esp_err_to_name(ret));
}

int rc522_interface_init(void)
{
	// Init the rst pin
	gpio_reset_pin(rst_io_num);
	gpio_set_direction(rst_io_num, GPIO_MODE_OUTPUT);
	gpio_set_level(rst_io_num, 1);

	spi_bus_config_t bus_config = {
		.miso_io_num = miso_io_num,
		.mosi_io_num = mosi_io_num,
		.sclk_io_num = sclk_io_num,

		// 禁用QSPI模式的 WP，HD 引脚
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,

		// 最大传输数据大小
		.max_transfer_sz = 64 * 8,
	};

	spi_device_interface_config_t dev_config = {
		.clock_speed_hz = SPI_MASTER_FREQ_10M,
		.mode = 0,
		.spics_io_num = -1,
		// 传输队列大小，决定了等待传输数据的数量
		.queue_size = 7,
	};

	//Initialize the SPI bus
	ret = spi_bus_initialize(host_id, &bus_config, dma_chan);
	log_if_err(ret, "spi_bus_initialize");

	ret = spi_bus_add_device(host_id, &dev_config, &spi_device_handle);
	log_if_err(ret, "spi_bus_add_device");

	// Init the cs pin
	gpio_reset_pin(cs_io_num);
	gpio_set_direction(cs_io_num, GPIO_MODE_OUTPUT);

	return 0;
}

int rc522_interface_free(void)
{
	gpio_reset_pin(rst_io_num);
	gpio_reset_pin(cs_io_num);

	// free spi
	ret = spi_bus_remove_device(spi_device_handle);
	log_if_err(ret, "spi_bus_remove_device");

	ret = spi_bus_free(host_id);
	log_if_err(ret, "spi_bus_free");

	return 0;
}

int rc522_set_rst(uint8_t level)
{
	gpio_set_level(rst_io_num, level);
	return 0;
}

int rc522_spi_set_cs(uint8_t level)
{
	gpio_set_level(cs_io_num, level);
	return 0;
}

int rc522_spi_write(const uint8_t *data, uint32_t data_len)
{
	spi_transaction_t t;

	// no need to send anything
	if (data_len == 0)
		return 0;

	// Zero out the transaction
	memset(&t, 0, sizeof(t));

	// Len is in bytes, transaction length is in bits.
	t.length = data_len * 8;

	t.tx_buffer = data;

	// Transmit!
	ret = spi_device_polling_transmit(spi_device_handle, &t);
	log_if_err(ret, "spi_device_polling_transmit");
	return 0;
}

int rc522_spi_read(uint8_t *data, uint32_t data_len)
{
	spi_transaction_t t;

	// no need to send anything
	if (data_len == 0)
		return 0;

	// Zero out the transaction
	memset(&t, 0, sizeof(t));

	// Len is in bytes, transaction length is in bits.
	t.length = data_len * 8;

	t.rx_buffer = data;

	// Transmit!
	ret = spi_device_polling_transmit(spi_device_handle, &t);
	log_if_err(ret, "spi_device_polling_transmit");

	return 0;
}

/**
 @brief 毫秒级延时函数
 @param time -[in] 延时时间（毫秒）
 @return 无
*/
void delay_ms(uint8_t time)
{
	vTaskDelay(time / portTICK_PERIOD_MS);
}